package CACA;

import java.util.ArrayList;
import java.util.Iterator;



public class ORTree{

	double[] weight;

	ORTreeNode root;
	public ORTreeNode getRoot() {
		return root;
	}
	ArrayList<ORTreeNode> oRList;
	
	public ORTree()
	{
		oRList = new ArrayList<ORTreeNode>();
		root = new ORTreeNode();
	}
	public int countRule()
	{
		return oRList.size();
	}
	
	
	public boolean insert(Rule rule)
	{
		return insert(root,rule, 0);
	}
	
	public void compact()
	{
		for(int i=0;i<oRList.size()-1;i++)
		{
			int j = i+1;
			ORTreeNode node2 = oRList.get(i);
			while(j<oRList.size())
			{
				ORTreeNode node1 = oRList.get(j);
				if(node1.ruleInfor.label == node2.ruleInfor.label && node1.isSubItemSet(node2) )
				{
					if(!findRule3(i, j, node1))
					{
						prune(oRList.remove(i));
						i--;
					}
					break;
				}
				j++;
			}
		}
	}
	private boolean findRule3(int i, int j, ORTreeNode node1) {
		for(int k=i+1;k<j;k++)
		{
			ORTreeNode node3 = oRList.get(k);
			if(node1.ruleInfor.label != node3.ruleInfor.label && node1.isSubItemSet(node3))
			{
				return true;
			}
		}
	
		return false;
	}
	public static void prune(ORTreeNode node)
	{
		if(node.childNodes.isEmpty())
		{
			pruneNode(node);
		}
		node.isLeaf = false;
		//node.ruleInfor = null;
	}
	public static void pruneNode(ORTreeNode node)
	{

		ORTreeNode father = node.fatherNode;
		if(father == null)
			return;
		father.childNodes.remove(node);
		if(!father.isLeaf && father.childNodes.isEmpty() )
		{
			pruneNode(father);
		}
	}
	public boolean insert(ORTreeNode node,Rule rule, int nodeIndex) {
		if (node.isLeaf && isMorePriority(rule, node.ruleInfor)<=0) {
			return false;
		}
		if (nodeIndex == rule.countItemSet()) {
			
			insert2ORList(node,rule);
			return true;
		}

		Item item = rule.getItemAt(nodeIndex);
		for (Iterator<ORTreeNode> iterator = node.childNodes.iterator(); iterator.hasNext();) {
			ORTreeNode childnode = (ORTreeNode) iterator.next();
			if (childnode.item.isEqual(item)) {
				return insert(childnode,rule, nodeIndex + 1);
			}
		}
		ORTreeNode childnode = new ORTreeNode(node,item);
		node.childNodes.add(childnode);
		return insert(childnode,rule, nodeIndex + 1);
		

	}
	public RuleInfo getRuleInfoAt(int i)
	{
		return oRList.get(i).getRuleInfor();
	}
	public void removeRuleAt( int i)
	{
		prune(oRList.remove(i));
	}
	private void insert2ORList(ORTreeNode node,Rule rule)
	{
		node.setRuleInfo(rule);
		for(int i=oRList.size()-1;i>=0;i--)
		{
			if(isMorePriority(rule, oRList.get(i).ruleInfor)>0)
			{		
				if(node.isSubItemSet(oRList.get(i)))
				{
					prune(oRList.remove(i));
				}		
			}
			else
			{
				if(oRList.get(i).isSubItemSet(node))
				{
					prune(node);
					return;
				}
				oRList.add(i+1, node);
				return;
			}
		}
		oRList.add(0, node);
	}

	public void putIndex()
	{
		int i=0;
		for (ORTreeNode node : oRList) {
			node.index = i++;
		}
	}
	private int isMorePriority(Rule rule, RuleInfo ruleInfo) {
		if(ruleInfo == null)
		{
			return 1;
		}
		if (rule.getConf() > ruleInfo.conf) {
			return 1;
		} else if (rule.getConf() == ruleInfo.conf) {
			double wsupp1 = rule.suppCount;
			double wsupp2 = ruleInfo.suppCount;
			if(weight != null){
				wsupp1 = rule.suppCount*weight[rule.label];
				wsupp2 = ruleInfo.suppCount*weight[ruleInfo.label];
			}
			if (wsupp1 > wsupp2) {
				return 1;
			} else if (rule.suppCount == ruleInfo.suppCount) {
				if (rule.itemSet.items.size() < ruleInfo.nItem)
					return 1;
				else if (rule.itemSet.items.size() == ruleInfo.nItem)
					return 0;
			}
		}
		return -1;
	}
	public int predict(int[] row)
	{

		for (Iterator<ORTreeNode> iterator = oRList.iterator(); iterator.hasNext();) {
			ORTreeNode node = (ORTreeNode) iterator.next();
			int label = node.ruleInfor.label;
			while(node.item != null)
			{
				if(row[node.item .attribute] != node.item.value)
				{
					break;
				}
				node = node.fatherNode;
			}
			if(node.item == null)
			{
				//System.out.println(i);
				return label;
			}
		}
		return -1;
		
	}
	public Rule getPredictedRule(int[] row)
	{
		for (Iterator<ORTreeNode> iterator = oRList.iterator(); iterator.hasNext();) {
					
			ItemSet itemSet = new ItemSet();
			ORTreeNode node = (ORTreeNode) iterator.next();
			double conf = node.ruleInfor.conf;
			int suppCount = node.ruleInfor.suppCount;
			
			int label = node.ruleInfor.label;
	
			while(node.item != null)
			{
				
				if(row[node.item .attribute] != node.item.value)
				{
					break;
				}
				itemSet.items.add(node.item);
				node = node.fatherNode;
			}
			if(node.item == null)
			{
				//System.out.println(i);
				Rule rule = new Rule(itemSet, label);
				rule.conf = conf;
				rule.suppCount = suppCount;
				return rule;
			}
		}
		return null;
		
	}
	public ArrayList<ORTreeNode> getoRList() {
		// TODO Auto-generated method stub
		return oRList;
	}
}
